﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;

namespace TCP_Toos
{
    public partial class Form1 : Form
    {
        #region 字段
        private string[] protocolStrs = { "UDP", "Tcp Server", "Tcp Client" };
        private string protocolWork = "";
        private Dictionary<string, string> dit;

        #region tcpclient 相关字段
        /// <summary>
        /// tcp client 连接状态
        /// </summary>
        private bool isTcpClientConnect = false;
        /// <summary>
        /// ip字符串
        /// </summary>
        private string serverIpstr ="";
        /// <summary>
        /// 端口号
        /// </summary>
        private int serverPort = -1;
        /// <summary>
        /// tcpClient 
        /// </summary>
        private TcpClient _tcpClient = null;
        private int receiveCount = 0;
        private int sendCount = 0;

        /// <summary>
        /// 接收数据缓冲区大小64K
        /// </summary>
        private const int ClientDefaultBufferSize = 64 * 1024;

        /// <summary>
        /// 接收数据缓冲区
        /// </summary>
        private readonly byte[] ClientReciveDataBuffer = new byte[ClientDefaultBufferSize];

        private enum ExitType
        {
            /// <summary>
            /// 用户退出
            /// </summary>
            ClientExit,
            /// <summary>
            /// 正常退出
            /// </summary>
            NormalExit,
            /// <summary>
            /// 异常关闭
            /// </summary>
            ExceptionExit
        };
        #endregion


        #endregion
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 界面加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            //加载协议说明
            protocol_cbb.DataSource = protocolStrs;
            //获取网卡信息
            dit = NetworkCardHelper.GetAllNetWorkCardDictionary();
            if (dit != null)
            {
                foreach (var item in dit.Values)
                {
                    //将IP赋值到下拉框
                    ip_cbb.Items.Add(item);
                }
                //默认索引0
                ip_cbb.SelectedIndex = 0;
            }
            port_txb.Text = "2001";
        }

        #region 界面控件操作
        /// <summary>
        /// 协议的选择
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void protocol_cbb_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (protocol_cbb.SelectedIndex)
            {
                case 0:
                    Ip_lab.Text = "本地IP地址";
                    Port_lab.Text = "本地端口号";
                    connect_btn.Text = "连接";
                    break;
                case 1:
                    Ip_lab.Text = "本地IP地址";
                    Port_lab.Text = "本地端口号";
                    connect_btn.Text = "开始监听";
                    break;
                case 2:
                    Ip_lab.Text = "服务器IP地址";
                    Port_lab.Text = "服务器端口号";
                    connect_btn.Text = "连接";
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 连接按钮操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void connect_btn_Click(object sender, EventArgs e)
        {
            switch (protocol_cbb.SelectedIndex)
            {
                case 0:
                    // UDP
                    break;
                case 1:
                    // TCP server

                    break;
                case 2:
                    // TCP client
                    connect_btn_tcpClient( sender,  e);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 清空计数操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cleanCount_tssl_Click(object sender, EventArgs e)
        {
            recivedCount_tssl.Text = "0";
            sendCount_tssl.Text = "0";

            receiveCount = 0;
            sendCount = 0;
        }

        /// <summary>
        /// 手动发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void handSend_btn_Click(object sender, EventArgs e)
        {
            switch (protocol_cbb.SelectedIndex)
            {
                case 0:
                    break;
                case 1:
                    break;
                case 2:
                    tcpClientSend();
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 连接的选择，根据协议的选择进行不同连接的设置
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void connect_btn_tcpClient(object sender, EventArgs e)
        {
            if (ip_cbb.Text == "" || port_txb.Text == "")
            {
                MessageBox.Show("IP和端口不能为空");
                return;
            }

            serverIpstr = ip_cbb.Text;
            serverPort = Convert.ToInt32(port_txb.Text);

            try
            {
                // 当前是未连接状态
                if (isTcpClientConnect == false)
                {
                    // 实例化客户端
                    _tcpClient = new TcpClient();
                    // 异步，启动链接
                    _tcpClient.BeginConnect(serverIpstr, serverPort, new AsyncCallback(Connected), _tcpClient.Client);

                }
                // 已连接状态
                else if (isTcpClientConnect == true && _tcpClient.Connected)
                {
                    // 断开链接
                    _tcpClient.Close();
                    // 更新断开的UI
                    ClientDisConnected(ExitType.ClientExit);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
        /// <summary>
        /// 自动清空接收区
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void autoCleanR_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (autoCleanR_chb.Checked)
            {
                timer1.Start();

            }
            else
            {
                timer1.Stop();
            }
        }

        /// <summary>
        /// 自动清空数据定时事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (receive_rtb.Text.Length > 4096)
            {
                receive_rtb.Text = "";
                recivedCount_tssl.Text = "0";
                receiveCount = 0;
            }
        }

        /// <summary>
        /// 自动发送选择处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void autoSendS_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (isTcpClientConnect == false && autoSendS_chb.CheckState == CheckState.Checked)
            {
                autoSendS_chb.CheckState = CheckState.Unchecked;
                if (timer2 != null)
                {
                    timer2.Enabled = false;
                    timer2.Stop();
                }
                MessageBox.Show("通信未连接！！");
                return;
            }
            // 串口打开
            if (isTcpClientConnect == true && autoSendS_chb.CheckState == CheckState.Checked)
            {
                autoTimer_txb.Enabled = false;
                handSend_btn.Enabled = false;
                int i = Convert.ToInt32(autoTimer_txb.Text);
                if (i < 10 || i > 60 * 1000)
                {
                    i = 1000;
                    autoTimer_txb.Text = "1000";
                    MessageBox.Show("自动发送数据的周期范围是10-60000毫秒", "警告");
                }
                timer2.Interval = i;
                timer2.Start();
            }
            else
            {
                handSend_btn.Enabled = true;
                autoTimer_txb.Enabled = true;
                if (timer2 != null)
                {
                    timer2.Stop();
                }
            }
        }

        /// <summary>
        /// 定时发送事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer2_Tick(object sender, EventArgs e)
        {
            switch (protocol_cbb.SelectedIndex)
            {
                case 0:
                    break;
                case 1:
                    break;
                case 2:
                    tcpClientSend();
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 清空发送区
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cleanS_btn_Click(object sender, EventArgs e)
        {
            send_rtb.Text = "";
            sendCount = 0;
            sendCount_tssl.Text = "0";
        }
        #endregion

        #region TCP client 相关的处理
        /// <summary>
        /// 连接成功回调处理
        /// </summary>
        /// <param name="e"></param>
        private void ClientConnected(Socket e)
        {
            // 更新链接状态
            isTcpClientConnect = true;

            // 格式化输出的信息字符串
            string info = string.Format("成功连接远程服务器：{0}",
                e.RemoteEndPoint.ToString());

            // 异步跨线程操作控件
            this.Invoke(new Action(() =>
            {
                message_tssl.Text = info;
                this.connect_btn.Text = "断开";
                this.connect_btn.Image = Properties.Resources.connect;
                ip_cbb.Enabled = false;
                port_txb.Enabled = false;
                protocol_cbb.Enabled = false;
            }));
        }
        /// <summary>
        /// 连接端口回调处理
        /// </summary>
        /// <param name="TypeOfExit"></param>
        private void ClientDisConnected(ExitType TypeOfExit)
        {
            isTcpClientConnect = false;
            // 判断退出是用户主动退出
            if (TypeOfExit == ExitType.ClientExit)
            {
                message_tssl.Text = "连接已断开！！";
            }
            // 判断退出是异常退出
            else if (TypeOfExit == ExitType.ExceptionExit)
            {
                message_tssl.Text = "服务器异常关闭！！";
                _tcpClient.Close();
            }
            // 其他作为异常服务器退出
            else
            {
                message_tssl.Text = "服务器已经关闭！！";
                _tcpClient.Close();

            }
            //调用基于——>Action的委托——>委托采用的是匿名函数实现
            this.Invoke(new Action(() => { 
                this.connect_btn.Text = "连接";
                this.connect_btn.Image = Properties.Resources.disconnect;
                ip_cbb.Enabled = true;
                port_txb.Enabled = true;
                protocol_cbb.Enabled = true;
            }));
        }
        /// <summary>
        /// 接收到数据回调处理
        /// </summary>
        /// <param name="recbuffer"></param>
        /// <param name="len"></param>
        private void ReceivedDataHandler(byte[] recbuffer, int len)
        {
            //调用委托去处理数据
            this.Invoke(new Action<byte[], int>((buffer, lenth) =>
            {
                if (hexR_chb.Checked == false)
                {
                    receive_rtb.AppendText(Encoding.Default.GetString(buffer, 0, lenth));
                    receiveCount += lenth;
                    recivedCount_tssl.Text = "" + receiveCount;

                }
                else
                {
                    byte[] data = new byte[lenth];                                                 
                    receiveCount += lenth;
                    recivedCount_tssl.Text = "" + receiveCount;                                          
                    Array.Copy(buffer, data, data.Length);
                    receive_rtb.AppendText(Transform.ToHexString(data, " "));
                }
            }
            ), new object[] { recbuffer, len });
        }

        /// <summary>
        /// 异步连接
        /// </summary>
        /// <param name="ar"></param>
        private void Connected(IAsyncResult ar)
        {
            // 获取参数
            Socket msocket = (Socket)ar.AsyncState;
            try
            {
                // 结束链接请求，必须调用EndConnect。重点。
                msocket.EndConnect(ar);

            }
            catch (SocketException ex)
            {
                isTcpClientConnect = false;
                if (ex.ErrorCode == 10061)
                    message_tssl.Text = "远程服务器拒绝接入";
                return;
            }
            finally
            {
                // nothing to do...
            }
            // 链接完成更新界面
            ClientConnected(msocket);
            // 启动数据读取，重点 socket下的BeginReceive，异步
            _tcpClient.Client.BeginReceive(ClientReciveDataBuffer, 0, ClientDefaultBufferSize, SocketFlags.None,
              new AsyncCallback(RecivedData), msocket);

        }
        /// <summary>
        /// 异步数据接收
        /// </summary>
        /// <param name="ar"></param>
        private void RecivedData(IAsyncResult ar)
        {
            // 断开状态就返回
            if (isTcpClientConnect == false) return;
            // 获取Socket对象
            Socket remote = (Socket)ar.AsyncState;
            try
            {
                // 获取接收数据的长度，EndReceive
                int reciveLength = remote.EndReceive(ar);
                //服务端关闭，正常退出
                if (reciveLength == 0)
                {
                    // UI更新
                    ClientDisConnected(ExitType.NormalExit);
                    return;
                }
                //接收数据更新到UI
                ReceivedDataHandler(ClientReciveDataBuffer, reciveLength);
                //继续接收，继续启动接收
                _tcpClient.Client.BeginReceive(ClientReciveDataBuffer, 0, ClientDefaultBufferSize, SocketFlags.None,
                    new AsyncCallback(RecivedData), _tcpClient.Client);
            }
            catch (SocketException ex)
            {
                if (10054 == ex.ErrorCode)
                {
                    //服务器强制的关闭连接，强制退出
                    message_tssl.Text = $"远程服务器关闭：{ex.ErrorCode}";
                }
                else
                {
                    message_tssl.Text = $"{ex.Message}";
                }
            }
            catch (ObjectDisposedException ex)
            {
                // 不处理异常
                if (ex != null)
                {
                    ex = null;
                }
            }
        }

       private void tcpClientSend()
        {
            if (isTcpClientConnect == false) return;
            /// 
            if (hexS_chb.Checked == false)
            {
                if (send_rtb.Text != "")
                {
                    Encoding gb = Encoding.GetEncoding("gb2312");
                    sendCount += gb.GetBytes(send_rtb.Text).Length;
                    sendCount_tssl.Text = "" + sendCount;
                    _tcpClient.Client.Send(Encoding.Default.GetBytes(send_rtb.Text));
                }
            }
            // 这里没有做hexstring的校验
            else
            {
                string hexstr = send_rtb.Text.Replace(" ", "");
                sendCount += Transform.ToBytes(hexstr).Length;
                sendCount_tssl.Text = ""+sendCount;
                _tcpClient.Client.Send(Transform.ToBytes(hexstr));
            }
        }

        #endregion

    }
}
